package eitwitter.evaluation;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import eitwitter.normalization.Normalizer;
import eitwitter.storage.Tweet;
import eitwitter.storage.Vocabulary;

public class Clustering {
	/** Map retenant pour chaque Tweet du fichier la liste de ses mots et leur fréquence d'apparition */
	HashMap<Tweet, HashMap<Integer, Double>> allTF;

	/** Ma retenant pour chaque mot du fichier le nombre de tweet le contenant */
	HashMap<Integer, Double> allIDF;

	/** Map retenant pour chaque tweet la liste de ses mots et leur tf.idf associé */
	HashMap<Tweet, HashMap<Integer, Double>> allTFIDF;

	/** Répartition des tweets */
	HashMap<Integer, ArrayList<Tweet>> evalCategories;
	
	/** Nombre de catégories */
	private int numberOfCat;
	
	/** Parametre du clustering */
	private double k;

	/** Methode de normalisation utilisee sur les tweets */
	private Normalizer normalizer;


	/** Reference vers le dictionnaire de mots du corpus d'entrainement */
	private Vocabulary vocabulary;

	
	public Clustering(int nbcat, double coef, Normalizer n, Vocabulary v){
		this.allTF = new HashMap<Tweet, HashMap<Integer,Double>>();
		this.allIDF = new HashMap<Integer, Double>();
		this.allTFIDF = new HashMap<Tweet, HashMap<Integer,Double>>();
		this.evalCategories = new HashMap<Integer, ArrayList<Tweet>>();
		this.numberOfCat = nbcat;
		this.k = coef;
		this.normalizer = n;
		this.vocabulary = v;
	}
	
	/**
	 * Lit le fichier contenant les tweets 
	 * @param file Fichier a traiter
	 */
	public void makeTfIDf(File file){

		try {
			// Ouverture du fichier
			InputStream ips = new FileInputStream(file);
			InputStreamReader ipsr = new InputStreamReader(ips);
			BufferedReader br = new BufferedReader(ipsr);

			// Traitement de la ligne en cours
			String line;
			while ((line=br.readLine())!=null){
				// Creation de l'objet Tweet pour la ligne lue
				Tweet t = Tweet.createFromString(line);
				this.makeTfAndIdf(t);
			}

			makeTfIdf();
			normaliser();


			// Fermeture des pointeurs
			br.close();
			ips.close();

		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	public void normaliser(){
		double sumTfIdf = 0.0;
		
		for(Entry<Tweet,  HashMap<Integer, Double>> entry : this.allTFIDF.entrySet()) {
			Tweet keyTweet = entry.getKey();
			HashMap<Integer, Double> valueAllTfIdf = entry.getValue();

			for(int j=0; j<this.vocabulary.size(); j++){
				if(valueAllTfIdf.containsKey(j))
					sumTfIdf+=valueAllTfIdf.get(j);
				else
					sumTfIdf+=this.k;
			}

			for(Entry<Integer,  Double> entryBis : this.allTFIDF.get(keyTweet).entrySet()) {
				Integer keyWord = entryBis.getKey();
				Double valueTfIdf = entryBis.getValue();

				(this.allTFIDF.get(keyTweet)).put(keyWord, valueTfIdf/sumTfIdf);
			}
		}
		
		}

		public void makeTfAndIdf(Tweet tweet){
			HashMap<Integer, Double> freq = new HashMap<Integer, Double>();
			ArrayList<Integer> dejaVu = new ArrayList<Integer>();



			// Decoupage du corps du tweet
			HashMap<String, Integer> tweetWords = normalizer.normalize(tweet.getContent());

			// Stockage de chacun des tokens
			for(Map.Entry<String, Integer> entry : tweetWords.entrySet()){

				// On essaye de recuperer l'identifiant du token dans le dico
				int id = vocabulary.getId(entry.getKey());

				// Si le mot n'est pas present
				if(id == -1){
					id = vocabulary.size();
					vocabulary.put(vocabulary.size(), entry.getKey());
				}

				// Si le mot n'est pas deja enregistre, on l'ajoute
				if(!freq.containsKey(id)){
					freq.put(id, 0.0);
				}
				// Sinon on incremente sa fréquence
				else{
					freq.put(id, freq.get(id)+1);
				}

				// Si le mot n'a pas deja ete vu pour ce tweet, on l'ajoute
				// et on incrément le nombre de documents le contenant
				if(!dejaVu.contains(id)){
					dejaVu.add(id);
					allIDF.put(id, allIDF.get(id)+1);

				}

				allTF.put(tweet, freq);
			}

		}


		public void makeTfIdf(){
			for(Entry<Tweet,  HashMap<Integer, Double>> entry : this.allTF.entrySet()) {
				Tweet keyTweet = entry.getKey();
				HashMap<Integer, Double> valueAllTf = entry.getValue();

				HashMap<Integer, Double> tfIdf = new HashMap<Integer, Double>();

				for(Entry<Integer,  Double> entryBis : valueAllTf.entrySet()) {
					Integer keyWord = entryBis.getKey();
					Double valueTf = entryBis.getValue();

					tfIdf.put(keyWord, valueTf*this.allIDF.get(keyWord));
				}

				this.allTFIDF.put(keyTweet, tfIdf);
			}

		}
		
		void kMoyenne(){
			for(int i=0; i<this.numberOfCat; i++){
				this.evalCategories.put(i, new ArrayList<Tweet>());
			}
			
			
			
		}


	}
